/**
 * @fileoverview
 * This script defines some MVC utilities.
 * @requires YAHOO.util.CustomEvent
 * @author <a href="http://purl.org/net/aliman">Alistair Miles</a>
 * @version $Revision:538 $ on $Date: 2008-08-14 10:36:17 +0100 (Thu, 14 Aug 2008) $ by $Author: aliman $
 * TODO license terms
 */
 
 
// create a namespace if not already defined
flyui.namespace("flyui.mvcutils");


/** 
 * Create a new instance.
 * @class
 * A generic model class for an MVC widget or application.
 * @constructor
 * @param {Object} definition (optional) the definition of the model 
 */
flyui.mvcutils.GenericModel2 = function( definition ) {
	
	/**
	 * @private
	 */
	this._state = null;
	
	/**
	 * @private
	 */
	this._events = null;
	
	/**
	 * @private
	 */
	this._properties = null;
	
	/**
	 * @private
	 */
	this._values = null;
	
	if (typeof definition != 'undefined') {
		// do initialisation
		this._init(definition);
	}
}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype.setDefinition = function( definition ) {
	this._init(definition);	
}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype._init = function( definition ) {

	// store properties
	this._properties = definition.properties;
	
	// store values
	this._values = definition.values;
	
	// init state
	this._state = {};
	definition.initialize(this._state);
	
	// init events
	this._events = {};
	for (var i=0; i<this._properties.length; i++) {
		var type = this._properties[i];
		this._events[type] = new YAHOO.util.CustomEvent(type, this);
	}

}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype.subscribe = function( property, listener, obj ) {

	// guard condition
	this._validateProperty(property);

	// do subscription
	this._events[property].subscribe(listener, obj);
		
}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype.subscribeAll = function( listener, obj ) {

	for (var i=0; i<this._properties.length; i++) {
		var property = this._properties[i];
		// pass through
		this.subscribe(property, listener, obj);
	}
	
}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype.get = function( property ) {

	// guard condition
	this._validateProperty(property);

	return this._state[property];
	
}


/**
 * TODO doc me
 */
flyui.mvcutils.GenericModel2.prototype.set = function( property, to ) {

	// guard condition
	this._validatePropertyValue(property, to);
	
	// store old value temporarily
	var from = this._state[property];
	
	// set new value
	this._state[property] = to;
	
	// notify listeners
	this._notify(property, from, to);

}


/**
 * TODO doc me
 * @private
 */
flyui.mvcutils.GenericModel2.prototype._validateProperty = function( property ) {

	var valid = false;

	for (var i=0; i<this._properties.length; i++) {
		if (this._properties[i] == property) valid = true;
	}

	if (!valid) {
		throw {
			name:"flyui.mvcutils.GenericModel2.InvalidPropertyNameError", 
			message:"Invalid property name: "+property
		};
	}

}


/**
 * TODO doc me
 * @private
 */
flyui.mvcutils.GenericModel2.prototype._validatePropertyValue = function( property, value ) {

	var valid = false;

	// check property first
	_this._validateProperty(property);
	
	// check values
	var values = this._values[property];
	
	if (values) {
		for (var i in values) {
			if (value == values[i]) {
				valid = true;
			}	
		}
	} else {
		// true if no values defined
		valid = true;
	}

	if (!valid) {
		throw {
			name:"flyui.mvcutils.GenericModel2.InvalidPropertyValueError", 
			message:"Invalid property value, property: "+property+", value: "+value
		};
	}
	
}


/**
 * TODO doc me
 * @private
 */
flyui.mvcutils.GenericModel2.prototype._notify = function( property, from, to ) {

	// property must already have been checked
	this._events[property].fire(from, to);
}
